/*
 * ControlUnit class handles program execution, instruction decoding, control flow and
 * machine state.
 * 
 * The Control Unit is composed of Program Counter Register, Instruction Register, Opcode
 * Register, Immediate Register, Condition Code Registers ( 0 - 3 ), Condition Code Index
 * Register and Boot, Stop, Exit and Step Registers.
 * 
 * For instruction processing, the CPU invokes the next operation on the control unit 
 * which begins the decode and execution process.  Upon next, the current instruction
 * indicated by the program counter is loaded into the instruction register and decoded.
 * Through decoding, the requisite instruction is determined, the appropriate 
 * registers of the system are populated and the associated instruction logic is invoked.
 * 
 * The Program Counter Register holds the address of the next instruction to be processed
 * 
 * The Instruction Register holds the instruction that is currently being processed.
 * 
 * The Condition Code Registers indicate system events that have arisen from processing.  
 * These include Underflow, Overflow, Division by Zero and Equal to events.
 * 
 * The Opcode and Immediate Registers are internal registers used for temporary storage
 * during processing.  Opcode allows the current instruction to be multiplexed to the 
 * appropriate registers.  Immediate holds a temporary value for adders or for return
 * flags.
 * 
 * Boot, Stop, Exit and Step registers indicate the state of system processing and determine
 * whether the system is in ready to handle instructions.  The Boot register indicates
 * whether or not the system is in boot up and can operate on instruction.  When in boot
 * the system cannot process instructions.  The Stop register indicates if the system 
 * processing has been suspended.  The Exit register indicates whether an event has been
 * raised that has compromised the integrity of the system and the system must be rebooted
 * to properly operate.  The Step register indicates if the process execution should proceed
 * only one operation at a time.
 * */

package cpu.components;

import cpu.datastores.*;
import cpu.datatypes.Bit;
import cpu.datatypes.Word;
import cpu.interfaces.EventListener;

enum InstructionFamily {
	IFAMILY_HALT,
	IFAMILY_ADDRESS_AND_REGISTER,
	IFAMILY_IMMEDIATE_AND_REGISTER,
	IFAMILY_ADDRESS_AND_CONDITION,
	IFAMILY_ADDRESS_ONLY,
	IFAMILY_IMMEDIATE_ONLY,
	IFAMILY_REGISTER_AND_REGISTER,
	IFAMILY_REGISTER_ONLY,
	IFAMILY_TRAP,
	IFAMILY_SR,
	IFAMILY_DEVICE,
	IFAMILY_NOP
}

public class ControlUnit {
	// Program Counter Register
	
	public static final int UNDERFLOW = 0;
	public static final int OVERFLOW = 1;
	public static final int DIVBYZERO = 2;
	public static final int EQUALORNOT = 3;
	
	public Register16 PC;
	
	// Instruction Register
	public Register16 IR;
	
	// Opcode Register
	public Register6 OP;
	
	// Immediate Register
	public Register6 IMMED;
	
	// Condition Code 0 Register (underflow)
	public Register1 CC0;
	
	// Condition Code 1 Register (overflow)
	public Register1 CC1;
	
	// Condition Code 2 Register (divbyzero)
	public Register1 CC2;
	
	// Condition Code 3 Register (equalornot)
	public Register1 CC3;
	
	// Condition Code Index Register
	public Register2 ICC;
	
	private CPU cpu;
	
	public boolean debug = false;

	public ControlUnit( ) {
		// for testing only.  
		// If the CU is to actually run then the CPU reference is necessary.
		
		PC = new Register16( );
		IR = new Register16( );
		OP = new Register6( );
		IMMED = new Register6( );
		CC0 = new Register1( );
		CC1 = new Register1( );
		CC2 = new Register1( );
		CC3 = new Register1( );
		ICC = new Register2( );
	}

	public ControlUnit( CPU cpu ) {
		PC = new Register16( );
		IR = new Register16( );
		OP = new Register6( );
		IMMED = new Register6( );
		CC0 = new Register1( );
		CC1 = new Register1( );
		CC2 = new Register1( );
		CC3 = new Register1( );
		ICC = new Register2( );
		
		this.cpu = cpu;
	}
	
	public void cc( Register2 icc, boolean value ) {
		int i = icc.toJavaInt( );
		
		switch( i ) {
		case 3:
			CC3.bit(0).value = value;
			break;
		case 2:
			CC2.bit(0).value = value;
			break;
		case 1:
			CC1.bit(0).value = value;
			break;
		case 0:
			CC0.bit(0).value = value;
			break;
		}
		updateConditionCodeIndicator( i );
	}
	
	public void cc( int icc, boolean value ) {
		assert( icc >= 0 && icc < 4 );
		
		ICC.fromJavaInt( icc );
		cc( ICC, value );
	}

	public Bit cc( Register2 icc ) {
		int i = icc.toJavaInt( );
		
		switch( i ) {
		case 3:
			return CC3.bit( 0 );
		case 2:
			return CC2.bit( 0 );
		case 1:
			return CC1.bit( 0 );
		case 0:
		default:
			return CC0.bit( 0 );
		}
	}
	
	public Bit cc( int icc ) {
		assert( icc >= 0 && icc < 4 );
		
		ICC.fromJavaInt( icc );
		return cc( ICC );
	}
	
	public void next( ) {
		// MAR <- PC
		cpu.memoryunit.MAR.fromWord( PC );
		updateMemoryAddressIndicator( );

		// Memory( get );
		cpu.memoryunit.get( );
		
		// IR <- MBR
		IR.fromWord( cpu.memoryunit.MBR );
		updateInstructionIndicator( );

		execute( IR );
	}
	
	private void execute( Word instruction ) {
		// extract the opcode
		for( int i = 0; i < 6; i++ ) {
			OP.bit( i ).value = instruction.bit( i ).value;
		}
		
		// decode the opcode and the rest of the instruction
		int op = OP.toJavaInt( );
		decode( op, instruction );
		
		switch( op ) {
		case 000:	//HLT
			HLT( );
			break;
		case 001:	//LDR
			LDR( );
			break;
		case 002:	//STR
			STR( );
			break;
		case 003:	//LDA
			LDA( );
			break;
		case 004:	//AMR
			AMR( );
			break;
		case 005:	//SMR
			SMR( );
			break;
		case 006:	//IAR
			IAR( );
			break;
		case 007:	//ISR
			ISR( );
			break;
		case 010:	//JZ
			JZ( );
			break;
		case 011:	//JNE
			JNE( );
			break;
		case 012:	//JCC
			JCC( );
			break;
		case 013:	//JMP
			JMP( );
			break;
		case 014:	//JSR
			JSR( );
			break;
		case 015:	//RFS
			RFS( );
			break;
		case 016:	//SOB
			SOB( );
			break;
		case 017:	//NOP
			NOP( );
			break;
		case 020:	//MUL
			MUL( );
			break;
		case 021:	//DIV
			DIV( );
			break;
		case 022:	//TST
			TST( );
			break;
		case 023:	//AND
			AND( );
			break;
		case 024:	//OR
			OR( );
			break;
		case 025:	//NOT
			NOT( );
			break;
		case 026:	//NOP
			NOP( );
			break;
		case 027:	//NOP
			NOP( );
			break;
		case 030:	//TRAP
			TRAP( );
			break;
		case 031:	//SRC
			SRC( );
			break;
		case 032:	//RRC
			RRC( );
			break;
		case 033:	//FADD
			FADD( );
			break;
		case 034:	//FSUB
			FSUB( );
			break;
		case 035:	//VADD
			VADD( );
			break;
		case 036:	//VSUB
			VSUB( );
			break;
		case 037:	//CNVRT
			CNVRT( );
			break;
		case 040:	//NOP
			NOP( );
			break;
		case 041:	//LDX
			LDX( );
			break;
		case 042:	//STX
			STX( );
			break;
		case 043:	//NOP
			NOP( );
			break;
		case 044:	//NOP
			NOP( );
			break;
		case 045:	//NOP
			NOP( );
			break;
		case 046:	//NOP
			NOP( );
			break;
		case 047:	//NOP
			NOP( );
			break;
		case 050:	//NOP
			NOP( );
			break;
		case 051:	//NOP
			NOP( );
			break;
		case 052:	//NOP
			NOP( );
			break;
		case 053:	//NOP
			NOP( );
			break;
		case 054:	//NOP
			NOP( );
			break;
		case 055:	//NOP
			NOP( );
			break;
		case 056:	//NOP
			NOP( );
			break;
		case 057:	//NOP
			NOP( );
			break;
		case 060:	//IN
			IN( );
			break;
		case 061:	//OUT
			OUT( );
			break;
		case 062:	//CHK
			CHK( );
			break;
		case 063:	//NOP
			NOP( );
			break;
		case 064:	//NOP
			NOP( );
			break;
		case 065:	//NOP
			NOP( );
			break;
		case 066:	//NOP
			NOP( );
			break;
		case 067:	//NOP
			NOP( );
			break;
		case 070:	//NOP
			NOP( );
			break;
		case 071:	//NOP
			NOP( );
			break;
		case 072:	//NOP
			NOP( );
			break;
		case 073:	//NOP
			NOP( );
			break;
		case 074:	//NOP
			NOP( );
			break;
		case 075:	//NOP
			NOP( );
			break;
		case 076:	//NOP
			NOP( );
			break;
		case 077:	//NOP
			NOP( );
			break;
		}
	}

	private void decode( int opcode, Word instruction ) {
		InstructionFamily ifamily = classify( opcode );
		
		switch( ifamily ) {
		case IFAMILY_HALT:
			decodeHaltInstruction( instruction );
			break;
		case IFAMILY_ADDRESS_AND_REGISTER:
			decodeAddressAndRegisterInstruction( instruction );
			break;
		case IFAMILY_IMMEDIATE_AND_REGISTER:
			decodeImmediateAndRegisterInstruction( instruction );
			break;
		case IFAMILY_ADDRESS_AND_CONDITION:
			decodeAddressAndConditionInstruction( instruction );
			break;
		case IFAMILY_ADDRESS_ONLY:
			decodeAddressOnlyInstruction( instruction );
			break;
		case IFAMILY_IMMEDIATE_ONLY:
			decodeImmediateOnlyInstruction( instruction );
			break;
		case IFAMILY_REGISTER_AND_REGISTER:
			decodeRegisterAndRegisterInstruction( instruction );
			break;
		case IFAMILY_REGISTER_ONLY:
			decodeRegisterOnlyInstruction( instruction );
			break;
		case IFAMILY_TRAP:
			decodeTrapInstruction( instruction );
			break;
		case IFAMILY_SR:
			decodeSRInstruction( instruction );
			break;
		case IFAMILY_DEVICE:
			decodeDeviceInstruction( instruction );
			break;
		case IFAMILY_NOP:
		default:
			break;
		}
	}
	
	private InstructionFamily classify( int opcode ) {
		switch( opcode ) {
		case 000:	//HLT
			return InstructionFamily.IFAMILY_HALT;
		case 001:	//LDR
			return InstructionFamily.IFAMILY_ADDRESS_AND_REGISTER;
		case 002:	//STR
			return InstructionFamily.IFAMILY_ADDRESS_AND_REGISTER;
		case 003:	//LDA
			return InstructionFamily.IFAMILY_ADDRESS_AND_REGISTER;
		case 004:	//AMR
			return InstructionFamily.IFAMILY_ADDRESS_AND_REGISTER;
		case 005:	//SMR
			return InstructionFamily.IFAMILY_ADDRESS_AND_REGISTER;
		case 006:	//IAR
			return InstructionFamily.IFAMILY_IMMEDIATE_AND_REGISTER;
		case 007:	//ISR
			return InstructionFamily.IFAMILY_IMMEDIATE_AND_REGISTER;
		case 010:	//JZ
			return InstructionFamily.IFAMILY_ADDRESS_AND_REGISTER;
		case 011:	//JNE
			return InstructionFamily.IFAMILY_ADDRESS_AND_REGISTER;
		case 012:	//JCC
			return InstructionFamily.IFAMILY_ADDRESS_AND_CONDITION;
		case 013:	//JMP
			return InstructionFamily.IFAMILY_ADDRESS_ONLY;
		case 014:	//JSR
			return InstructionFamily.IFAMILY_ADDRESS_ONLY;
		case 015:	//RFS
			return InstructionFamily.IFAMILY_IMMEDIATE_ONLY;
		case 016:	//SOB
			return InstructionFamily.IFAMILY_ADDRESS_AND_REGISTER;
		case 017:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 020:	//MUL
			return InstructionFamily.IFAMILY_REGISTER_AND_REGISTER;
		case 021:	//DIV
			return InstructionFamily.IFAMILY_REGISTER_AND_REGISTER;
		case 022:	//TST
			return InstructionFamily.IFAMILY_REGISTER_AND_REGISTER;
		case 023:	//AND
			return InstructionFamily.IFAMILY_REGISTER_AND_REGISTER;
		case 024:	//OR
			return InstructionFamily.IFAMILY_REGISTER_AND_REGISTER;
		case 025:	//NOT
			return InstructionFamily.IFAMILY_REGISTER_ONLY;
		case 026:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 027:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 030:	//TRAP
			return InstructionFamily.IFAMILY_TRAP;
		case 031:	//SRC
			return InstructionFamily.IFAMILY_SR;
		case 032:	//RRC
			return InstructionFamily.IFAMILY_SR;
		case 033:	//FADD
			return InstructionFamily.IFAMILY_ADDRESS_AND_REGISTER;
		case 034:	//FSUB
			return InstructionFamily.IFAMILY_ADDRESS_AND_REGISTER;
		case 035:	//VADD
			return InstructionFamily.IFAMILY_ADDRESS_AND_REGISTER;
		case 036:	//VSUB
			return InstructionFamily.IFAMILY_ADDRESS_AND_REGISTER;
		case 037:	//CNVRT
			return InstructionFamily.IFAMILY_ADDRESS_AND_REGISTER;
		case 040:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 041:	//LDX
			return InstructionFamily.IFAMILY_ADDRESS_ONLY;
		case 042:	//STX
			return InstructionFamily.IFAMILY_ADDRESS_ONLY;
		case 043:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 044:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 045:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 046:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 047:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 050:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 051:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 052:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 053:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 054:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 055:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 056:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 057:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 060:	//IN
			return InstructionFamily.IFAMILY_DEVICE;
		case 061:	//OUT
			return InstructionFamily.IFAMILY_DEVICE;
		case 062:	//CHK
			return InstructionFamily.IFAMILY_DEVICE;
		case 063:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 064:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 065:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 066:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 067:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 070:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 071:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 072:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 073:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 074:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 075:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 076:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		case 077:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		default:	//NOP
			return InstructionFamily.IFAMILY_NOP;
		}
	}
	
	private void decodeHaltInstruction( Word instruction ) {
		// halt has no additional fields so nothing else to decode per ISA
		
	}
	
	private void decodeAddressAndRegisterInstruction( Word instruction ) {
		// opcode already populated: instruction.bits[0-5]
		// I: instruction.bit[6]
		// X: instruction.bit[7]
		// RI0: instruction.bits[8-9]
		// ADDR: instruction.bits[10-15]
		
		cpu.addressunit.IND.bit( 0 ).value = instruction.bit( 6 ).value;
		cpu.addressunit.IX.bit( 0 ).value = instruction.bit( 7 ).value;
		for( int i = 0; i < 2; i++ )
			cpu.registerfile.RSR0.bit( i ).value = instruction.bit( 8 + i ).value;
		for( int i = 0; i < 6; i++ ) 
			cpu.addressunit.ADDR.bit( i ).value = instruction.bit( 10 + i ).value;
	}
	
	private void decodeImmediateAndRegisterInstruction( Word instruction ) {
		// opcode already populated: instruction.bits[0-5]
		// RI0: instruction.bits[8-9]
		// IMMED: instruction.bits[10-15]
		
		for( int i = 0; i < 2; i++ )
			cpu.registerfile.RSR0.bit( i ).value = instruction.bit( 8 + i ).value;
		for( int i = 0; i < 6; i++ ) 
			IMMED.bit( i ).value = instruction.bit( 10 + i ).value;
	}
	
	private void decodeAddressAndConditionInstruction( Word instruction ) {
		// opcode already populated: instruction.bits[0-5]
		// I: instruction.bit[6]
		// X: instruction.bit[7]
		// CCI: instruction.bits[8-9]
		// ADDR: instruction.bits[10-15]
		
		cpu.addressunit.IND.bit( 0 ).value = instruction.bit( 6 ).value;
		cpu.addressunit.IX.bit( 0 ).value = instruction.bit( 7 ).value;
		for( int i = 0; i < 2; i++ )
			ICC.bit( i ).value = instruction.bit( 8 + i ).value;
		for( int i = 0; i < 6; i++ ) 
			cpu.addressunit.ADDR.bit( i ).value = instruction.bit( 10 + i ).value;
	}
	
	private void decodeAddressOnlyInstruction( Word instruction ) {
		// opcode already populated: instruction.bits[0-5]
		// I: instruction.bit[6]
		// X: instruction.bit[7]
		// ADDR: instruction.bits[10-15]
		
		cpu.addressunit.IND.bit( 0 ).value = instruction.bit( 6 ).value;
		cpu.addressunit.IX.bit( 0 ).value = instruction.bit( 7 ).value;
		for( int i = 0; i < 6; i++ ) 
			cpu.addressunit.ADDR.bit( i ).value = instruction.bit( 10 + i ).value;
	}
	
	private void decodeImmediateOnlyInstruction( Word instruction ) {
		// opcode already populated: instruction.bits[0-5]
		// IMMED: instruction.bits[10-15]
		
		for( int i = 0; i < 6; i++ ) 
			IMMED.bit( i ).value = instruction.bit( 10 + i ).value;
	}
	
	private void decodeRegisterAndRegisterInstruction( Word instruction ) {
		// opcode already populated: instruction.bits[0-5]
		// RI0: instruction.bits[6-7]
		// RI1: instruction.bits[8-9]
		
		for( int i = 0; i < 2; i++ )
			cpu.registerfile.RSR0.bit( i ).value = instruction.bit( 6 + i ).value;
		for( int i = 0; i < 2; i++ )
			cpu.registerfile.RSR1.bit( i ).value = instruction.bit( 8 + i ).value;
	}
	
	private void decodeRegisterOnlyInstruction( Word instruction ) {
		// opcode already populated: instruction.bits[0-5]
		// RI0: instruction.bits[6-7]
		
		for( int i = 0; i < 2; i++ )
			cpu.registerfile.RSR0.bit( i ).value = instruction.bit( 6 + i ).value;
	}
	
	private void decodeTrapInstruction( Word instruction ) {
		// opcode already populated: instruction.bits[0-5]
		// RI0: instruction.bits[8-9]
		
		for( int i = 0; i < 2; i++ )
			cpu.registerfile.RSR0.bit( i ).value = instruction.bit( 8 + i ).value;
	}
	
	private void decodeSRInstruction( Word instruction ) {
		// opcode already populated: instruction.bits[0-5]
		// L: instruction.bit[6]
		// RI0: instruction.bits[7-8]
		// A: instruction.bit[9]
		// COUNT: instruction.bits[12-15]
		
		cpu.sru.SRD.bit( 0 ).value = instruction.bit( 6 ).value;
		for( int i = 0; i < 2; i++ )
			cpu.registerfile.RSR0.bit( i ).value = instruction.bit( 7 + i ).value;
		cpu.sru.SRT.bit( 0 ).value = instruction.bit( 9 ).value;
		for( int i = 0; i < 4; i++ ) 
			cpu.sru.SRCT.bit( i ).value = instruction.bit( 12 + i ).value;
	}
	
	private void decodeDeviceInstruction( Word instruction ) {
		// opcode already populated: instruction.bits[0-5]
		// RI0: instruction.bits[8-9]
		// DEVICEID: instruction.bits[11-15]
		
		for( int i = 0; i < 2; i++ )
			cpu.registerfile.RSR0.bit( i ).value = instruction.bit( 8 + i ).value;
		for( int i = 0; i < 5; i++ )
			cpu.deviceunit.DID.bit( i ).value = instruction.bit( 11 + i ).value;
	}
	
	private void HLT( ) {
		if( debug ) trace( "HLT" );
		
		cpu.statusunit.STOP.bit( 0 ).value = true;
	}
	
	private void LDR( ) {
		// EA( )
		cpu.addressunit.EA( );
		updateAddressIndicator( );
		
		// MAR <- EAB
		cpu.memoryunit.MAR.fromRegister( cpu.addressunit.EAB );
		updateMemoryAddressIndicator( );
		
		// Memory( get )
		cpu.memoryunit.get( );
		
		// R( RSR0 ) <- MBR
		cpu.registerfile.set( cpu.registerfile.RSR0, cpu.memoryunit.MBR );
		updateRegisterFileIndicator( cpu.registerfile.RSR0 );
		
		if( debug ) trace( "LDR" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void STR( ) {
		// EA( )
		cpu.addressunit.EA( );
		updateAddressIndicator( );

		// MAR <- EAB
		cpu.memoryunit.MAR.fromWord( cpu.addressunit.EAB );
		updateMemoryAddressIndicator( );

		// MBR <- R( RSR0 )
		cpu.memoryunit.MBR.fromWord( cpu.registerfile.get( cpu.registerfile.RSR0 ) );
		
		// Memory( put )
		cpu.memoryunit.put( );
		
		if( debug ) trace( "STR" );
	
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void LDA( ) {
		// EA( )
		cpu.addressunit.EA( );
		updateAddressIndicator( );

		// R( RSR0 ) <- EAB
		cpu.registerfile.set( cpu.registerfile.RSR0, cpu.addressunit.EAB );
		updateRegisterFileIndicator( cpu.registerfile.RSR0 );
		
		if( debug ) trace( "LDA" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void AMR( ) {
		// EA( )
		cpu.addressunit.EA( );
		updateAddressIndicator( );

		// MAR <- EAB
		cpu.memoryunit.MAR.fromWord( cpu.addressunit.EAB );
		updateMemoryAddressIndicator( );

		// Memory( get )
		cpu.memoryunit.get( );
		
		// signed
		cpu.alu.ALS.bit( 0 ).value = true;
		
		// ALO0 <- R( RSR0 )
		cpu.alu.ALO0.fromWord( cpu.registerfile.get( cpu.registerfile.RSR0 ) );

		// ALO1 <- MBR
		cpu.alu.ALO1.fromWord( cpu.memoryunit.MBR );

		// ALU( add );
		cpu.alu.add( );
		
		// R( RSR0 ) <- ALR0
		cpu.registerfile.set( cpu.registerfile.RSR0, cpu.alu.ALR.wordLow );
		updateRegisterFileIndicator( cpu.registerfile.RSR0 );
		
		// Note: condition code( OVERFLOW ) may be set by ALU

		if( debug ) trace( "AMR" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void SMR( ) {
		// EA( )
		cpu.addressunit.EA( );
		updateAddressIndicator( );

		// MAR <- EAB
		cpu.memoryunit.MAR.fromWord( cpu.addressunit.EAB );
		updateMemoryAddressIndicator( );

		// Memory( get )
		cpu.memoryunit.get( );

		// signed
		cpu.alu.ALS.bit( 0 ).value = true;

		// ALO0 <- R( RSR0 )
		cpu.alu.ALO0.fromWord( cpu.registerfile.get( cpu.registerfile.RSR0 ) );

		// ALO1 <- MBR
		cpu.alu.ALO1.fromWord( cpu.memoryunit.MBR );

		// ALU( subtract );
		cpu.alu.subtract( );
		
		// R( RSR0 ) <- ALR0
		cpu.registerfile.set( cpu.registerfile.RSR0, cpu.alu.ALR.wordLow );
		updateRegisterFileIndicator( cpu.registerfile.RSR0 );
		
		// Note: condition code( OVERFLOW ) may be set by ALU
		
		if( debug ) trace( "SMR" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void IAR( ) {
		if( IMMED.toJavaInt( ) > 0 ) {
			// optimization to save cycles
		
			// if( R( RSR0 ) == 0 )
			if( cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( ) == 0 ) {
				// optimization to save cycles
				
				// R( RSR0 ) <- IMMED
				cpu.registerfile.get( cpu.registerfile.RSR0 ).fromSignedInteger( IMMED.toJavaInt( ) );
				updateRegisterFileIndicator( cpu.registerfile.RSR0 );
			} else {
				// signed
				cpu.alu.ALS.bit( 0 ).value = true;

				// ALO0 <- R( RSR0 )
				cpu.alu.ALO0.fromWord( cpu.registerfile.get( cpu.registerfile.RSR0 ) );

				// ALO1 <- IMMED
				// sign not a problem here because IMMED is smaller than a byte
				cpu.alu.ALO1.fromSignedInteger( IMMED.toJavaInt( ) );

				// ALU( add );
				cpu.alu.add( );
				
				// R( RSR0 ) <- ALR0
				cpu.registerfile.set( cpu.registerfile.RSR0, cpu.alu.ALR.wordLow );
				updateRegisterFileIndicator( cpu.registerfile.RSR0 );

				// Note: condition code( OVERFLOW ) may be set by ALU
			}
		}

		if( debug ) trace( "IAR" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void ISR( ) {
		if( IMMED.toJavaInt( ) > 0 ) {
			// optimization to save cycles
		
			// if( R( RSR0 ) == 0 )
			if( cpu.registerfile.get( cpu.registerfile.RSR0 ).toJavaInt( ) == 0 ) {
				// optimization to save cycles
				
				// R( RSR0 ) <- IMMED
				cpu.registerfile.get( cpu.registerfile.RSR0 ).fromJavaInt( IMMED.toJavaInt( ) );
			} else {
				// signed
				cpu.alu.ALS.bit( 0 ).value = true;

				// ALO0 <- R( RSR0 )
				cpu.alu.ALO0.fromWord( cpu.registerfile.get( cpu.registerfile.RSR0 ) );

				// ALO1 <- IMMED
				// sign not a problem here because IMMED is smaller than a byte
				cpu.alu.ALO1.fromSignedInteger( IMMED.toJavaInt( ) );

				// ALU( subtract );
				cpu.alu.subtract( );
				
				// R( RSR0 ) <- ALR0
				cpu.registerfile.set( cpu.registerfile.RSR0, cpu.alu.ALR.wordLow );
				updateRegisterFileIndicator( cpu.registerfile.RSR0 );
				
				// Note: condition code( OVERFLOW ) may be set by ALU
			}
		}

		if( debug ) trace( "ISR" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void JZ( ) {
		// if( R( RSR0 ) == 0 )
		if( cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( ) == 0 ) {
			
			// EA( )
			cpu.addressunit.EA( );
			updateAddressIndicator( );
			
			if( debug ) trace( "JZ" );
			
			// PC <- EAB
			PC.fromRegister( cpu.addressunit.EAB );
			updateProgramCounterIndicator( );
		} else {
		// else
			
			if( debug ) trace( "JZ" );
			
			// PC <- PC + 2
			PC.increment( );
			PC.increment( );
			updateProgramCounterIndicator( );
		}
	}
	
	private void JNE( ) {
		// if( R( RSR0 ) != 0 )
		if( cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( ) != 0 ) {
			
			// EA( )
			cpu.addressunit.EA( );
			updateAddressIndicator( );

			if( debug ) trace( "JNE" );
			
			// PC <- EAB
			PC.fromRegister( cpu.addressunit.EAB );
			updateProgramCounterIndicator( );
		} else {
		// else

			if( debug ) trace( "JNE" );
			
			// PC <- PC + 2
			PC.increment( );
			PC.increment( );
			updateProgramCounterIndicator( );
		}
	}
	
	private void JCC( ) {
		// if( CC(ICC) != 0 )
		if( cc( ICC ).value != false ) {
			
			// EA( )
			cpu.addressunit.EA( );
			updateAddressIndicator( );
			
			if( debug ) trace( "JCC" );
			
			// PC <- EAB
			PC.fromRegister( cpu.addressunit.EAB );
			updateProgramCounterIndicator( );
		} else {
		// else
			
			if( debug ) trace( "JCC" );
			
			// PC <- PC + 2
			PC.increment( );
			PC.increment( );
			updateProgramCounterIndicator( );
		}
	}
	
	private void JMP( ) {
		// EA( )
		cpu.addressunit.EA( );
		updateAddressIndicator( );
		
		if( debug ) trace( "JMP" );
		
		// PC <- EAB
		PC.fromRegister( cpu.addressunit.EAB );
		updateProgramCounterIndicator( );
	}
	
	private void JSR( ) {
		// R( 3 ) <- PC + 2
		cpu.registerfile.R3.fromRegister( PC );
		cpu.registerfile.R3.increment( );
		cpu.registerfile.R3.increment( );
		updateRegisterFileIndicator( 3 );
		
		// EA( )
		cpu.addressunit.EA( );
		updateAddressIndicator( );

		if( debug ) trace( "JSR" );
		
		// PC <- EAB
		PC.fromRegister( cpu.addressunit.EAB );
		updateProgramCounterIndicator( );
	}
	
	private void RFS( ) {
		// R( 0 ) <- IMMED
		cpu.registerfile.R0.fromSignedInteger( IMMED.toJavaInt() );
		updateRegisterFileIndicator( 0 );
		
		if( debug ) trace( "RFS" );
		
		// PC <- R( 3 )
		PC.fromRegister( cpu.registerfile.R3 );
		updateProgramCounterIndicator( );
	}
	
	private void SOB( ) {
		// R( RSR0 ) <- R( RSR0 ) - 1
		int accumulator = cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger();
		accumulator = accumulator - 1;
		cpu.registerfile.get( cpu.registerfile.RSR0 ).fromSignedInteger( accumulator );
		updateRegisterFileIndicator( cpu.registerfile.RSR0 );
			
		// if( R( RSR0 ) > 0 )
		if( cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( ) > 0 ) {
			
			// EA( )
			cpu.addressunit.EA( );
			updateAddressIndicator( );
			
			if( debug ) trace( "SOB" );

			// PC <- EAB
			PC.fromRegister( cpu.addressunit.EAB );
			updateProgramCounterIndicator( );
		} else {
		// else
			
			if( debug ) trace( "SOB" );

			// PC <- PC + 2
			PC.increment( );
			PC.increment( );
			updateProgramCounterIndicator( );
		}
	}
	
	private void MUL( ) {
		//RSR0 has to be either 0 or 2
		//RSR1 has to be either 0 or 2
		//high bits into RSR0
		//low bits into RSR0+1 -> either R1 or R3
		
		int rsr0 = cpu.registerfile.RSR0.toJavaInt( );
		int rsr1 = cpu.registerfile.RSR1.toJavaInt( );
		
		if( ( rsr0 != 0 && rsr0 != 2 ) || ( rsr1 != 0 && rsr1 != 2 ) || ( rsr0 == rsr1 ) ) {
			// machine fault - bad ALU operand
			if( debug ) trace( "TRAP" );
			
			// Machine Fault 3 = Bad ALU Operand
			cpu.statusunit.MFR.fromJavaInt( 3 );
			updateMachineFaultIndicator( );
			
			// raise fault
			cpu.statusunit.fault( );
			return;
		}
		// otherwise good to go
		
		//calculate where to put the results
		int rhighbits = rsr0;
		int rlowbits = rsr0+1;
		
		// ALO0 <- R( RSR0 )
		cpu.alu.ALO0.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR0 ) );
		
		// ALO1 <- R( RSR1 )
		cpu.alu.ALO1.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR1 ) );
		
		// ALU( multiply )
		cpu.alu.multiply( );
		
		// Note condition codes set by ALU
		
		// R( RSR0 ) <- ALR0
		cpu.registerfile.setDirect( rhighbits, cpu.alu.ALR.wordHigh );
		updateRegisterFileIndicator( rhighbits );
		
		// R( RSR0+1 ) <- ALR1
		cpu.registerfile.setDirect( rlowbits, cpu.alu.ALR.wordLow );
		updateRegisterFileIndicator( rlowbits );
		
		if( debug ) trace( "MUL" );

		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void DIV( ) {
		//RSR0 has to be either 0 or 2
		//RSR1 has to be either 0 or 2
		//quotient into RSR0
		//remainder into RSR0+1 -> either R1 or R3
		
		int rsr0 = cpu.registerfile.RSR0.toJavaInt( );
		int rsr1 = cpu.registerfile.RSR1.toJavaInt( );
		
		if( ( rsr0 != 0 && rsr0 != 2 ) || ( rsr1 != 0 && rsr1 != 2 ) || ( rsr0 == rsr1 ) ) {
			// machine fault - bad ALU operand
			if( debug ) trace( "TRAP" );
			
			// Machine Fault 3 = Bad ALU Operand
			cpu.statusunit.MFR.fromJavaInt( 3 );
			updateMachineFaultIndicator( );
			
			// raise fault
			cpu.statusunit.fault( );
			return;
		}
		// otherwise good to go
		
		//calculate where to put the results
		int rquotient = rsr0;
		int rremainder = rsr0+1;
		
		// ALO0 <- R( RSR0 )
		cpu.alu.ALO0.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR0 ) );
		
		// ALO1 <- R( RSR1 )
		cpu.alu.ALO1.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR1 ) );
		
		// ALU( divide )
		cpu.alu.divide( );
		
		// Note condition codes set by ALU
		
		// R( RSR0 ) <- ALR0
		cpu.registerfile.setDirect( rquotient, cpu.alu.ALR.wordLow );
		updateRegisterFileIndicator( rquotient );
		
		// R( RSR0+1 ) <- ALR1
		cpu.registerfile.setDirect( rremainder, cpu.alu.ALR.wordHigh );
		updateRegisterFileIndicator( rremainder );
		
		if( debug ) trace( "DIV" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void TST( ) {
		// ALO0 <- R( RSR0 )
		cpu.alu.ALO0.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR0 ) );
		
		// ALO1 <- R( RSR1 )
		cpu.alu.ALO1.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR1 ) );
		
		// ALU( equivalent )
		cpu.alu.equivalent( );
		
		// Note condition codes set by ALU
		
		if( debug ) trace( "TST" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void AND( ) {
		// ALO0 <- R( RSR0 )
		cpu.alu.ALO0.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR0 ) );
		
		// ALO1 <- R( RSR1 )
		cpu.alu.ALO1.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR1 ) );
		
		// ALU( and )
		cpu.alu.and( );
		
		// R( RSR0 ) <- ALR0
		cpu.registerfile.get( cpu.registerfile.RSR0 ).fromRegister( cpu.alu.ALR.wordLow );
		updateRegisterFileIndicator( cpu.registerfile.RSR0 );
		
		if( debug ) trace( "AND" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void OR( ) {
		// ALO0 <- R( RSR0 )
		cpu.alu.ALO0.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR0 ) );
		
		// ALO1 <- R( RSR1 )
		cpu.alu.ALO1.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR1 ) );
		
		// ALU( or )
		cpu.alu.or( );
		
		// R( RSR0 ) <- ALR0
		cpu.registerfile.get( cpu.registerfile.RSR0 ).fromRegister( cpu.alu.ALR.wordLow );
		updateRegisterFileIndicator( cpu.registerfile.RSR0 );
		
		if( debug ) trace( "OR" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void NOT( ) {
		// ALO0 <- R( RSR0 )
		cpu.alu.ALO0.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR0 ) );
		
		// ALU( not )
		cpu.alu.not( );
		
		// R( RSR0 ) <- ALR0
		cpu.registerfile.get( cpu.registerfile.RSR0 ).fromRegister( cpu.alu.ALR.wordLow );
		updateRegisterFileIndicator( cpu.registerfile.RSR0 );
		
		if( debug ) trace( "NOT" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void TRAP( ) {
		// MAR <- 0
		cpu.memoryunit.MAR.fromJavaInt( 0 );
		updateMemoryAddressIndicator( );
		
		// Memory( get )
		cpu.memoryunit.get( );
		
		// if( R( RSR0 ) > 15 )
		if( cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( ) > 15 ) {
			// machine fault
			if( debug ) trace( "TRAP" );
			
			// Machine Fault 1 = Illegal Trap code
			cpu.statusunit.MFR.fromJavaInt( 1 );
			updateMachineFaultIndicator( );
			
			// raise fault
			cpu.statusunit.fault( );
			return;
		} else {
			// else valid trap

			// R( 3 ) <- PC + 2
			cpu.registerfile.R3.fromRegister( PC );
			cpu.registerfile.R3.increment( );
			cpu.registerfile.R3.increment( );
			updateRegisterFileIndicator( 3 );

			if( debug ) trace( "TRAP" );

			// PC <- MBR + R(RSR0) + R(RSR0)
			PC.fromSignedInteger( cpu.memoryunit.MBR.toSignedInteger( ) + 2 * cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( ) );
			updateProgramCounterIndicator( );			
		}
	}
	
	private void SRC( ) {
		// SRB <- R( RSR0 )
		cpu.sru.SRB.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR0 ) );
		
		// SRU( shift )
		cpu.sru.shift( );
		
		// Note condition codes set by SRU
		
		// R( RSR0 ) <- SRB
		cpu.registerfile.set( cpu.registerfile.RSR0, cpu.sru.SRB );
		updateRegisterFileIndicator( cpu.registerfile.RSR0 );
		
		if( debug ) trace( "SRC" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void RRC( ) {
		// SRB <- R( RSR0 )
		cpu.sru.SRB.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR0 ) );
		
		// SRU( rotate )
		cpu.sru.rotate( );
		
		// R( RSR0 ) <- SRB
		cpu.registerfile.set( cpu.registerfile.RSR0, cpu.sru.SRB );
		updateRegisterFileIndicator( cpu.registerfile.RSR0 );
		
		if( debug ) trace( "RRC" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void FADD( ) {
		// EA( )
		cpu.addressunit.EA( );
		updateAddressIndicator( );
		
		// MAR <- EAB
		cpu.memoryunit.MAR.fromRegister( cpu.addressunit.EAB );
		updateMemoryAddressIndicator( );
		
		// Memory( get )
		cpu.memoryunit.get( );
		
		// FPO0 <- R( RSR0 )
		cpu.fpu.FPO0.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR0 ) );
		
		// FPO1 <- MBR
		cpu.fpu.FPO0.fromRegister( cpu.memoryunit.MBR );
		
		// FPU( add )
		cpu.fpu.add( );
		
		// Note condition codes set by FPU
		
		// R( RSR0 ) <- FPR0
		cpu.registerfile.set( cpu.registerfile.RSR0, cpu.fpu.FPR );
		updateRegisterFileIndicator( cpu.registerfile.RSR0 );
		
		if( debug ) trace( "FADD" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void FSUB( ) {
		// EA( )
		cpu.addressunit.EA( );
		updateAddressIndicator( );
		
		// MAR <- EAB
		cpu.memoryunit.MAR.fromRegister( cpu.addressunit.EAB );
		updateMemoryAddressIndicator( );
		
		// Memory( get )
		cpu.memoryunit.get( );
		
		// FPO0 <- R( RSR0 )
		cpu.fpu.FPO0.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR0 ) );
		
		// FPO1 <- MBR
		cpu.fpu.FPO0.fromRegister( cpu.memoryunit.MBR );
		
		// FPU( subtract )
		cpu.fpu.add( );
		
		// Note condition codes set by FPU
		
		// R( RSR0 ) <- FPR0
		cpu.registerfile.set( cpu.registerfile.RSR0, cpu.fpu.FPR );
		updateRegisterFileIndicator( cpu.registerfile.RSR0 );
		
		if( debug ) trace( "FSUB" );
		
		// PC <- PC + 2 
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void VADD( ) {
		// EA( )
		cpu.addressunit.EA( );
		updateAddressIndicator( );
		
		int address0 = cpu.addressunit.EAB.toSignedInteger();
		int address1 = address0 + 2;
		
		cpu.vu.VO0.fromSignedInteger( address0 );
		cpu.vu.VO1.fromSignedInteger( address1 );
		
		cpu.vu.VL.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR0 ) );
		
		cpu.vu.add( );
		
		if( debug ) trace( "VADD" );
		
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void VSUB( ) {
		// EA( )
		cpu.addressunit.EA( );
		updateAddressIndicator( );
		
		int address0 = cpu.addressunit.EAB.toSignedInteger();
		int address1 = address0 + 2;
		
		cpu.vu.VO0.fromSignedInteger( address0 );
		cpu.vu.VO1.fromSignedInteger( address1 );
		
		cpu.vu.VL.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR0 ) );
		
		cpu.vu.subtract( );
		
		if( debug ) trace( "VSUB" );
		
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void CNVRT( ) {
		// to be determined
		
		if( debug ) trace( "CNVRT" );
		
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void LDX( ) {
		// EA( )
		cpu.addressunit.EA( );
		updateAddressIndicator( );
		
		// MAR <- EAB
		cpu.memoryunit.MAR.fromRegister( cpu.addressunit.EAB );
		updateMemoryAddressIndicator( );
		
		// Memory( get )
		cpu.memoryunit.get( );
		
		// X0 <- MBR
		cpu.addressunit.X0.fromRegister( cpu.memoryunit.MBR );
		updateBaseAddressIndicator( );
		
		if( debug ) trace( "LDX" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void STX( ) {
		// EA( )
		cpu.addressunit.EA( );
		updateAddressIndicator( );
		
		// MAR <- EAB
		cpu.memoryunit.MAR.fromRegister( cpu.addressunit.EAB );
		updateMemoryAddressIndicator( );
		
		// MBR <- X0
		cpu.memoryunit.MBR.fromRegister( cpu.addressunit.X0 );
		
		// Memory( put )
		cpu.memoryunit.put( );
		
		if( debug ) trace( "STX" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void IN( ) {
		// Device( get )
		cpu.deviceunit.get( );
		
		// R( RSR0 ) <- DBR
		cpu.registerfile.set( cpu.registerfile.RSR0 , cpu.deviceunit.DBR );
		updateRegisterFileIndicator( cpu.registerfile.RSR0 );
		
		if( debug ) trace( "IN" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void OUT( ) {
		// DBR <- R( RSR0 )
		cpu.deviceunit.DBR.fromRegister( cpu.registerfile.get( cpu.registerfile.RSR0 ) );
		
		// Device( put )
		cpu.deviceunit.put( );
		
		if( debug ) trace( "OUT" );
		
		// PC <- PC + 2
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void CHK( ) {
		// Device( status )
		cpu.deviceunit.status( );
		
		// R( RSR0 ) <- DSR
		cpu.registerfile.set( cpu.registerfile.RSR0 , cpu.deviceunit.DSR );
		updateRegisterFileIndicator( cpu.registerfile.RSR0 );
		
		if( debug ) trace( "CHK" );
		
		// PC <- PC + 2 
		PC.increment( );
		PC.increment( );
		updateProgramCounterIndicator( );
	}
	
	private void NOP( ) {
		if( debug ) trace( "NOP" );
		
		// Machine Fault 2 = Illegal Opcode
		cpu.statusunit.MFR.fromJavaInt( 2 );
		updateMachineFaultIndicator( );

		// raise fault
		cpu.statusunit.fault( );
	}
	
	private String pad( String s, char ch, int n  ) {
		if ( s.length( ) < n ) {
			char[] chasn = new char[n];
			int i = 0;
			while ( i < s.length( ) ) {
				chasn[i] = s.charAt( i );
				i++;
			}
			while ( i < n ) {
				chasn[i] = ch;
				i++;
			}
			s = new String(chasn);
		}
		return s;
	}
	
	private void trace( String op ) {
		String out = PC.toSignedInteger( ) + ":" + op;
		
		int col0 = 0;
		int txt1col = 30;
		int op1col = 45;
		int txt2col = 50;
		int op2col = 65;
		int txt3col = 70;
		
		if( op.compareTo( "HLT" ) == 0 ) {
			
		} else if( op.compareTo( "LDR" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += cpu.memoryunit.MAR.toSignedInteger( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
		} else if( op.compareTo( "STR" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += cpu.memoryunit.MAR.toSignedInteger( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
		} else if( op.compareTo( "LDA" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += "EAB" + ":" + cpu.addressunit.EAB.toSignedInteger( );
		} else if( op.compareTo( "AMR" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.alu.ALO0.toSignedInteger( );
			out = pad( out, ' ', op2col );
			out += "+";
			out = pad( out, ' ', txt3col );
			out += cpu.memoryunit.MAR.toSignedInteger( ) + ":" + cpu.alu.ALO1.toSignedInteger( );
		} else if( op.compareTo( "SMR" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.alu.ALO0.toSignedInteger( );
			out = pad( out, ' ', op2col );
			out += "-";
			out = pad( out, ' ', txt3col );
			out += cpu.memoryunit.MAR.toSignedInteger( ) + ":" + cpu.alu.ALO1.toSignedInteger( );
		} else if( op.compareTo( "IAR" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.controlunit.IMMED.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.alu.ALO0.toSignedInteger( );
			out = pad( out, ' ', op2col );
			out += "+";
			out = pad( out, ' ', txt3col );
			out += "IMMED:" + cpu.alu.ALO1.toSignedInteger( );
		} else if( op.compareTo( "ISR" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.controlunit.IMMED.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.alu.ALO0.toSignedInteger( );
			out = pad( out, ' ', op2col );
			out += "-";
			out = pad( out, ' ', txt3col );
			out += "IMMED:" + cpu.alu.ALO1.toSignedInteger( );
		} else if( op.compareTo( "JZ" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			if( cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( ) == 0 ) {
				out += "PC:" + cpu.addressunit.EAB.toSignedInteger( );	
			} else {
				out += "PC:" + ( PC.toSignedInteger( ) + 2 );
			}
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
		} else if( op.compareTo( "JNE" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			if( cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( ) != 0 ) {
				out += "PC:" + cpu.addressunit.EAB.toSignedInteger( );	
			} else {
				out += "PC:" + ( PC.toSignedInteger( ) + 2 );
			}
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += "R" + cpu.registerfile.RSR0.toJavaInt() + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger();
		} else if( op.compareTo( "JCC" ) == 0 ) {
			out += "," + ICC.toJavaInt( );
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			if( cc( ICC ).value != false ) {
				out += "PC:" + cpu.addressunit.EAB.toSignedInteger( );	
			} else {
				out += "PC:" + ( PC.toSignedInteger( ) + 2 );
			}
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += "CC" + ICC.toJavaInt() + ":" + cc( ICC ).value;;
		} else if( op.compareTo( "JMP" ) == 0 ) {
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "PC:" + cpu.addressunit.EAB.toSignedInteger( );	
		} else if( op.compareTo( "JSR" ) == 0 ) {
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "PC:" + cpu.addressunit.EAB.toSignedInteger( );	
			out = pad( out, ' ', txt2col );
			out += "R0:" + cpu.registerfile.R0.toSignedInteger( );
			out = pad( out, ' ', txt3col );
			out += "R3:" + cpu.registerfile.R3.toSignedInteger( );
		} else if( op.compareTo( "RFS" ) == 0 ) {
			out += "," + IMMED.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "PC:" + cpu.registerfile.R3.toSignedInteger( );	
		} else if( op.compareTo( "SOB" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			if( cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( ) > 0 ) {
				out += "PC:" + cpu.addressunit.EAB.toSignedInteger( );	
			} else {
				out += "PC:" + ( PC.toSignedInteger( ) + 2 );
			}
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
		} else if( op.compareTo( "MUL" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.registerfile.RSR1.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "(low) R" + ( cpu.registerfile.RSR0.toJavaInt( ) + 1 ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0.toJavaInt( ) + 1 ).toSignedInteger( ); 
			out += "\t";
			out += "(hi) R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.alu.ALO0.toSignedInteger( ); 
			out += "\t*\t";
			out += "R" + cpu.registerfile.RSR1.toJavaInt( ) + ":" + cpu.alu.ALO1.toSignedInteger( );
		} else if( op.compareTo( "DIV" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.registerfile.RSR1.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "(q) R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( ); 
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.alu.ALO0.toSignedInteger( ); 
			out += "\t/\t";
			out += "R" + cpu.registerfile.RSR1.toJavaInt( ) + ":" + cpu.alu.ALO1.toSignedInteger( );
			out += "\t\t";
			out += "(r) R" + (cpu.registerfile.RSR0.toJavaInt( ) + 1 ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0.toJavaInt( ) + 1 ).toSignedInteger( );
			out += "\t\t<-\t";
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.alu.ALO0.toSignedInteger( ); 
			out += "\t%\t";
			out += "R" + cpu.registerfile.RSR1.toJavaInt( ) + ":" + cpu.alu.ALO1.toSignedInteger( );
		} else if( op.compareTo( "TST" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.registerfile.RSR1.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "CC3:" + this.CC3.bit( 0 ).value; 
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
			out = pad( out, ' ', op2col );
			out += "?=";
			out = pad( out, ' ', txt3col );
			out += "R" + cpu.registerfile.RSR1.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR1 ).toSignedInteger( );
		} else if( op.compareTo( "AND" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.registerfile.RSR1.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "R:" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
			out += "\t\t<-\t";
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.alu.ALO0.toSignedInteger( ); 
			out = pad( out, ' ', op2col );
			out += "AND";
			out = pad( out, ' ', txt3col );
			out += "R" + cpu.registerfile.RSR1.toJavaInt( ) + ":" + cpu.alu.ALO1.toSignedInteger( );
		} else if( op.compareTo( "OR" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.registerfile.RSR1.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "R:" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.alu.ALO0.toSignedInteger( ); 
			out = pad( out, ' ', op2col );
			out += "OR";
			out = pad( out, ' ', txt3col );
			out += "R" + cpu.registerfile.RSR1.toJavaInt( ) + ":" + cpu.alu.ALO1.toSignedInteger( );
		} else if( op.compareTo( "NOT" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "R:" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += "NOT R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.alu.ALO0.toSignedInteger( ); 
		} else if( op.compareTo( "TRAP" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
		} else if( op.compareTo( "SRC" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.sru.SRD.bit( 0 ).value + "," + cpu.sru.SRT.bit( 0 ).value + "," + cpu.sru.SRCT.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
		} else if( op.compareTo( "RRC" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.sru.SRD.bit( 0 ).value + "," + cpu.sru.SRT.bit( 0 ).value + "," + cpu.sru.SRCT.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "R" + cpu.registerfile.RSR0.toJavaInt( ) + ":" + cpu.registerfile.get( cpu.registerfile.RSR0 ).toSignedInteger( );
		} else if( op.compareTo( "FADD" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
		} else if( op.compareTo( "FSUB" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
		} else if( op.compareTo( "VADD" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
		} else if( op.compareTo( "VSUB" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
		} else if( op.compareTo( "CNVRT" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
		} else if( op.compareTo( "LDX" ) == 0 ) {
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "X0:" + cpu.addressunit.X0.toSignedInteger( );
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += cpu.memoryunit.MAR.toSignedInteger( ) + ":" + cpu.memoryunit.MBR.toSignedInteger( );
		} else if( op.compareTo( "STX" ) == 0 ) {
			out += "," + cpu.addressunit.IND.bit( 0 ).value + "," + cpu.addressunit.IX.bit( 0 ).value + "," + cpu.addressunit.ADDR.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += cpu.memoryunit.MAR.toSignedInteger( ) + ":" + cpu.memoryunit.MBR.toSignedInteger( );
			out = pad( out, ' ', op1col );
			out += "<-";
			out = pad( out, ' ', txt2col );
			out += "X0:" + cpu.addressunit.X0.toSignedInteger( );
		} else if( op.compareTo( "IN" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.deviceunit.DID.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "DBR:" + cpu.deviceunit.DBR.toSignedInteger( );
		} else if( op.compareTo( "OUT" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.deviceunit.DID.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "DBR:" + cpu.deviceunit.DBR.toSignedInteger( );
		} else if( op.compareTo( "CHK" ) == 0 ) {
			out += "," + cpu.registerfile.RSR0.toJavaInt( );
			out += "," + cpu.deviceunit.DID.toJavaInt( );
			out = pad( out, ' ', txt1col );  
			out += ";";
			out += "DSR:" + cpu.deviceunit.DSR.toSignedInteger( );
			out = pad( out, ' ', txt2col );  
			out += "DBR:" + cpu.deviceunit.DBR.toSignedInteger( );
		} else if( op.compareTo( "NOP" ) == 0 ) {
			
		}
		System.out.println( out );
	}
	
	public void updateRegisterFileIndicator( Register2 RSR ) {
		int r = RSR.toJavaInt( );
		switch( r ) {
		case 3:	
			cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDR3.ordinal( ) );
			cpu.deviceunit.DBR.fromRegister( cpu.registerfile.R3 );
			break;
		case 2:
			cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDR2.ordinal( ) );
			cpu.deviceunit.DBR.fromRegister( cpu.registerfile.R2 );
			break;			
		case 1:
			cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDR1.ordinal( ) );
			cpu.deviceunit.DBR.fromRegister( cpu.registerfile.R1 );
			break;
		default:
		case 0:
			cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDR0.ordinal( ) );
			cpu.deviceunit.DBR.fromRegister( cpu.registerfile.R0 );
			break;
		}
		cpu.deviceunit.put( );
		cpu.idle( );
	}
	
	public void updateRegisterFileIndicator( int rsr ) {
		switch( rsr ) {
		case 3:	
			cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDR3.ordinal( ) );
			cpu.deviceunit.DBR.fromRegister( cpu.registerfile.R3 );
			break;
		case 2:
			cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDR2.ordinal( ) );
			cpu.deviceunit.DBR.fromRegister( cpu.registerfile.R2 );
			break;			
		case 1:
			cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDR1.ordinal( ) );
			cpu.deviceunit.DBR.fromRegister( cpu.registerfile.R1 );
			break;
		default:
		case 0:
			cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDR0.ordinal( ) );
			cpu.deviceunit.DBR.fromRegister( cpu.registerfile.R0 );
			break;
		}
		cpu.deviceunit.put( );
		cpu.idle( );
	}
	
	public void updateMemoryAddressIndicator( ) {
		cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDMAR.ordinal( ) );
		cpu.deviceunit.DBR.fromRegister( cpu.memoryunit.MAR );
		cpu.deviceunit.put( );
		cpu.idle( );
	}
	
	public void updateMemoryBufferIndicator( ) {
		cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDMBR.ordinal( ) );
		cpu.deviceunit.DBR.fromRegister( cpu.memoryunit.MBR );
		cpu.deviceunit.put( );
		cpu.idle( );
	}
	
	public void updateAddressIndicator( ) {
		cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDEA.ordinal( ) );
		cpu.deviceunit.DBR.fromRegister( cpu.addressunit.EAB );
		cpu.deviceunit.put( );
		cpu.idle( );
	}
	
	public void updateInstructionIndicator( ) {
		cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDIR.ordinal( ) );
		cpu.deviceunit.DBR.fromRegister( cpu.addressunit.EAB );
		cpu.deviceunit.put( );
		cpu.idle( );
	}
	
	public void updateProgramCounterIndicator( ) {
		cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDPC.ordinal( ) );
		cpu.deviceunit.DBR.fromRegister( PC );
		cpu.deviceunit.put( );
		cpu.idle( );
	}
	
	public void updateBootIndicator( ) {
		cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDBOOT.ordinal( ) );
		cpu.deviceunit.DBR.fromRegister( cpu.statusunit.BOOT );
		cpu.deviceunit.put( );
		cpu.idle( );
	}
	
	public void updateStopIndicator( ) {
		cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDSTOP.ordinal( ) );
		cpu.deviceunit.DBR.fromRegister( cpu.statusunit.STOP );
		cpu.deviceunit.put( );
		cpu.idle( );
	}
	
	public void updateRunIndicator( ) {
		cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDRUN.ordinal( ) );
		if( cpu.statusunit.STOP.bit( 0 ).value == true )
			cpu.deviceunit.DBR.fromJavaInt( 0 );
		else
			cpu.deviceunit.DBR.fromJavaInt( 1 );
		cpu.deviceunit.put( );
		cpu.idle( );
	}
	
	public void updateConditionCodeIndicator( Register2 CCI ) {
		int cc = CCI.toJavaInt( );
		switch( cc ) {
		case 3:	
			cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDCC3.ordinal( ) );
			cpu.deviceunit.DBR.fromRegister( CC3 );
			break;
		case 2:
			cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDCC2.ordinal( ) );
			cpu.deviceunit.DBR.fromRegister( CC2 );
			break;			
		case 1:
			cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDCC1.ordinal( ) );
			cpu.deviceunit.DBR.fromRegister( CC1 );
			break;
		default:
		case 0:
			cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDCC0.ordinal( ) );
			cpu.deviceunit.DBR.fromRegister( CC0 );
			break;
		}
		cpu.deviceunit.put( );
		// cpu.idle( ); 	// no idle
	}
	
	public void updateConditionCodeIndicator( int cc ) {
		switch( cc ) {
		case 3:	
			cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDCC3.ordinal( ) );
			cpu.deviceunit.DBR.fromRegister( CC3 );
			break;
		case 2:
			cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDCC2.ordinal( ) );
			cpu.deviceunit.DBR.fromRegister( CC2 );
			break;			
		case 1:
			cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDCC1.ordinal( ) );
			cpu.deviceunit.DBR.fromRegister( CC1 );
			break;
		default:
		case 0:
			cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDCC0.ordinal( ) );
			cpu.deviceunit.DBR.fromRegister( CC0 );
			break;
		}
		cpu.deviceunit.put( );
		// cpu.idle( ); 	// no idle
	}
	
	public void updateMachineStatusIndicator( ) {
		cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDMSR.ordinal( ) );
		cpu.deviceunit.DBR.fromRegister( cpu.statusunit.MSR );
		cpu.deviceunit.put( );
		cpu.idle( );
	}
	
	public void updateMachineFaultIndicator( ) {
		cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDMFR.ordinal( ) );
		cpu.deviceunit.DBR.fromRegister( cpu.statusunit.MFR );
		cpu.deviceunit.put( );
		cpu.idle( );
	}
	
	public void updateBaseAddressIndicator( ) {
		cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDX0.ordinal( ) );
		cpu.deviceunit.DBR.fromRegister( cpu.addressunit.X0 );
		cpu.deviceunit.put( );
		cpu.idle( );
	}
	
	public void updateCacheAddressIndicator( ) {
		cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDCACHEMAR.ordinal( ) );
		cpu.deviceunit.DBR.fromRegister( cpu.cacheunit.MAR );
		cpu.deviceunit.put( );
		cpu.idle( );
	}
	
	public void updateCacheBufferIndicator( ) {
		cpu.deviceunit.DID.fromJavaInt( system.device.Identifiers.DEVICE_LEDCACHEMBR.ordinal( ) );
		cpu.deviceunit.DBR.fromRegister( cpu.cacheunit.MBR );
		cpu.deviceunit.put( );
		cpu.idle( );
	}
	
	public void updateDeviceIndexIndicator( ) {
		cpu.idle( );
	}
	
	public void updateDeviceBufferIndicator( ) {
		cpu.idle( );
	}
	
	public void updateDeviceStatusIndicator( ) {
		cpu.idle( );
	}
	
	public void updateALUOperandIndicator( ) {
		cpu.idle( );
	}
	
	public void updateALUOperationIndicator( ) {
		cpu.idle( );
	}
	
	public void updateALUResultIndicator( ) {
		cpu.idle( );
	}
	
	public void updateSRUOperandIndicator( ) {
		cpu.idle( );
	}
	
	public void updateSRUOperationIndicator( ) {
		cpu.idle( );
	}
	
	public void updateSRUResultIndicator( ) {
		cpu.idle( );
	}
	
	public void updateFPUOperandIndicator( ) {
		cpu.idle( );
	}
	
	public void updateFPUOperationIndicator( ) {
		cpu.idle( );
	}
	
	public void updateFPUResultIndicator( ) {
		cpu.idle( );
	}
	
	public void updateVUOperandIndicator( ) {
		cpu.idle( );
	}
	
	public void updateVUOperationIndicator( ) {
		cpu.idle( );
	}
	
	public void updateVUResultIndicator( ) {
		cpu.idle( );
	}
}
